package cn.tedu.single;
/*本类用于测试单例设计模式2--懒汉式*/
/*总结：
* 关于单例设计模式的两种实现方式
* 1.饿汉式：不管你用不用这个类的对象，都会直接先创建一个
* 2.懒汉式：先不给你创建这个类的对象，等你需要的时候再帮你创建--利用了延迟加载的思想
* 延迟加载的思想：是指不会在第一时间就把对象创建好来占用内存，而是什么时候用到，什么时候再去创建对象
* 3.线程安全问题：是指共享资源有线程并发的数据安全隐患，可以通过加锁的方式解决[同步代码块/同步方法]
* */
public class Singleton2 {
    public static void main(String[] args) {
        //6.通过类名调用getSing（）方法获取本类对象
        Mysingle2 single1 = Mysingle2.getMySingle2();
        Mysingle2 single2 = Mysingle2.getMySingle2();
        //7.测试获取到的这两个引用类型变量是否相等
        System.out.println(single1==single2);
    }
}
//0.创建自己的单例程序
class Mysingle2{
    //1.私有化构造方法，为了防止外部调用构造方法直接创建本类对象
    private Mysingle2(){  }
   //2.在类的内部创建好引用类型变量（延迟加载的思想）--注意私有化
    //5.2本类的引用类型变量也需要static修饰
    static private Mysingle2 single2;
    //7.2
   static Object o = new Object();
    /*问题：程序中有共享资源single2，并且有多条语句（3句）操作了共享资源
    * 此时single2共享资源在多线程环境下一定会存在多线程数据安全隐患
    * 解决方案1：同步代码块[加锁，范围是操作共享资源的所有代码]
    * 解决方案2：同步方法[如果方法中的所有代码都需要被同步，那么这个方法可以修饰成同步方法]
    * 注意事项：锁对象在静态方法中，不可以使用this，因为静态资源优先于对象加载
    * 锁对象可以使用外部创建好的唯一的锁对象o，但请注意，需要是静态的，静态只能调用静态
    * */
    //3.对外提供公共的全局访问点
    //5.1  注意要用static修饰
    //7.1将方法修饰成同步方法
    synchronized static public Mysingle2 getMySingle2(){
        //4.当用户调用此方法时，才说明用到这个对象了，那么我们就把这个对象返回
        /*注意：这里需要增加一个判断，
        如果调用方法时single2的值为null，说明之前没有new过，保存的是默认值
        这时才需要new对象，如果single2的值不为null，直接return single2即可*/
        //7.2可以将操作共享资源的多条语句放入同步代码块中
        synchronized (o) {
            if (single2 == null) {
                single2 = new Mysingle2();//没有对象时才创建，并赋值给single2
            }
            return single2;//有对象则直接返回single2
        }
    }
}